package com.ittao.taoaicodeapp.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.ittao.taoaicodeapp.mapper.ChatHistoryMapper;
import com.ittao.taoaicodeapp.service.AppService;
import com.ittao.taoaicodeapp.service.ChatHistoryService;
import com.ittao.taoaicodecommon.constant.UserConstant;
import com.ittao.taoaicodecommon.exception.ErrorCode;
import com.ittao.taoaicodecommon.exception.ThrowUtils;
import com.ittao.taoaicodemodel.model.dto.chathistory.ChatHistoryQueryRequest;
import com.ittao.taoaicodemodel.model.entity.App;
import com.ittao.taoaicodemodel.model.entity.ChatHistory;
import com.ittao.taoaicodemodel.model.entity.User;
import com.ittao.taoaicodemodel.model.enums.ChatHistoryMessageTypeEnum;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 对话历史 服务层实现。
 *
 * @author <a href="https://gitee.com/it-heima-ht">程序员 Tao</a>
 */
@Service
@Slf4j
public class ChatHistoryServiceImpl extends ServiceImpl<ChatHistoryMapper, ChatHistory> implements ChatHistoryService {

    @Resource
    @Lazy
    private AppService appService;

    /**
     * 添加对话历史
     * @param appId 应用 id
     * @param message 消息
     * @param messageType 消息类型
     * @param userId 用户 id
     * @return 是否添加成功
     */
    @Override
    public boolean addChatMessage(Long appId, String message, String messageType, Long userId) {
        // 基础校验
        ThrowUtils.throwIf(appId == null || appId <= 0, ErrorCode.PARAMS_ERROR, "应用ID不能为空");
        ThrowUtils.throwIf(StrUtil.isBlank(message), ErrorCode.PARAMS_ERROR, "消息内容不能为空");
        ThrowUtils.throwIf(StrUtil.isBlank(messageType), ErrorCode.PARAMS_ERROR, "消息类型不能为空");
        ThrowUtils.throwIf(userId == null || userId <= 0, ErrorCode.PARAMS_ERROR, "用户ID不能为空");

        // 验证消息类型是否有效
        ChatHistoryMessageTypeEnum messageTypeEnum = ChatHistoryMessageTypeEnum.getEnumByValue(messageType);
        ThrowUtils.throwIf(messageTypeEnum == null, ErrorCode.PARAMS_ERROR, "不支持的消息类型");

        // 插入数据库
        ChatHistory chatHistory = ChatHistory.builder()
                .appId(appId)
                .message(message)
                .messageType(messageTypeEnum.getValue())
                .userId(userId)
                .build();
        return this.save(chatHistory);
    }

    /**
     * 根据应用 ID 删除对应的对话历史
     * @param appId 应用 ID
     * @return 是否删除成功
     */
    @Override
    public boolean deleteByAppId(Long appId) {
        ThrowUtils.throwIf(appId == null || appId <= 0, ErrorCode.PARAMS_ERROR, "应用ID不能为空");
        QueryWrapper queryWrapper = QueryWrapper.create()
                .eq("appId", appId);
        return this.remove(queryWrapper);
    }

    /**
     * 分页获取某应用的对话历史
     *
     * @param appId          应用 id
     * @param pageSize       每页大小
     * @param lastCreateTime 上次最后一条数据的创建时间，第一页传 null
     * @param loginUser     登录用户
     * @return 应用的对话历史分页
     */
    @Override
    public Page<ChatHistory> listAppChatHistoryByPage(Long appId, int pageSize,
                                                      LocalDateTime lastCreateTime,
                                                      User loginUser) {
        // 验证权限：只有应用创建者和管理员可以查看
        App app = appService.getById(appId);
        ThrowUtils.throwIf(app == null, ErrorCode.NOT_FOUND_ERROR, "应用不存在");
        boolean isAdmin = UserConstant.ADMIN_ROLE.equals(loginUser.getUserRole());
        boolean isCreator = app.getUserId().equals(loginUser.getId());
        // 既不是管理员也不是创建者，无权查看对话历史
        ThrowUtils.throwIf(!isAdmin && !isCreator, ErrorCode.NO_AUTH_ERROR, "无权查看该应用的对话历史");
        // 构建查询条件
        ChatHistoryQueryRequest queryRequest = new ChatHistoryQueryRequest();
        queryRequest.setAppId(appId);
        queryRequest.setLastCreateTime(lastCreateTime);
        QueryWrapper queryWrapper = this.getQueryWrapper(queryRequest);
        // 查询数据
        return this.page(Page.of(1, pageSize), queryWrapper);
    }

    /**
     * 加载对话历史到内存
     * @param appId 应用 id
     * @param chatMemory 对话记忆对象
     * @param maxCount 最大加载数量
     * @return 实际加载数量
     */
    @Override
    public int loadChatHistoryToMemory(Long appId, MessageWindowChatMemory chatMemory, int maxCount) {
        try {
            QueryWrapper queryWrapper = QueryWrapper.create()
                    .eq(ChatHistory::getAppId, appId)
                    .orderBy(ChatHistory::getCreateTime, true)
                    .limit(1, maxCount); // 只加载最新后偏移1条的 maxCount 条记录，因为是先加载传入信息到数据库，再加载历史记录到内存的
            List<ChatHistory> historyList = this.list(queryWrapper);
            if (CollUtil.isEmpty(historyList)) {
                return 0;
            }
            // 反转列表，按时间顺序正序添加到内存（老的在前，新的在后）
            historyList = historyList.reversed();
            // 按照时间顺序将消息添加到记忆中
            int loadedCount = 0;
            // 先清理历史缓存，防止重复加载
            chatMemory.clear();
            for (ChatHistory history : historyList) {
                if (ChatHistoryMessageTypeEnum.USER.getValue().equals(history.getMessageType())) {
                    chatMemory.add(UserMessage.from(history.getMessage()));
                } else if (ChatHistoryMessageTypeEnum.AI.getValue().equals(history.getMessageType())) {
                    chatMemory.add(AiMessage.from(history.getMessage()));
                }
                loadedCount++;
            }
            log.info("加载对话历史到内存，appId: {}, 加载数量: {}", appId, loadedCount);
            return loadedCount;
        } catch (Exception e) {
            log.error("加载对话历史到内存失败，appId: {}, 错误信息: {}", appId, e.getMessage(), e);
            // 加载失败不影响系统运行，只是没有历史上下文
            return 0;
        }
    }

    /**
     * 获取查询包装类
     * MyBatis-Flex会自动忽略NULL值参数，无需手动判断
     *
     * @param chatHistoryQueryRequest 历史对话查询请求
     * @return 查询包装类
     */
    @Override
    public QueryWrapper getQueryWrapper(ChatHistoryQueryRequest chatHistoryQueryRequest) {
        QueryWrapper queryWrapper = QueryWrapper.create();
        if (chatHistoryQueryRequest == null) {
            return queryWrapper.orderBy("createTime", false);
        }
        
        Long id = chatHistoryQueryRequest.getId();
        String message = chatHistoryQueryRequest.getMessage();
        String messageType = chatHistoryQueryRequest.getMessageType();
        Long appId = chatHistoryQueryRequest.getAppId();
        Long userId = chatHistoryQueryRequest.getUserId();
        LocalDateTime lastCreateTime = chatHistoryQueryRequest.getLastCreateTime();
        String sortField = chatHistoryQueryRequest.getSortField();
        String sortOrder = chatHistoryQueryRequest.getSortOrder();
        
        queryWrapper.eq("id", id)
                .eq("messageType", messageType)
                .eq("appId", appId)
                .eq("userId", userId);
        
        // LIKE查询需要特殊处理：避免空字符串和过长字符串的性能问题
        if (StrUtil.isNotBlank(message) && message.length() <= 100) {
            queryWrapper.like("message", message);
        }
        
        // 游标分页：基于时间戳的高效分页方案
        if (lastCreateTime != null) {
            queryWrapper.lt("createTime", lastCreateTime);
        }
        
        // 动态排序：支持自定义排序字段
        if (StrUtil.isNotBlank(sortField)) {
            queryWrapper.orderBy(sortField, "ascend".equals(sortOrder));
        } else {
            queryWrapper.orderBy("createTime", false);
        }
        
        return queryWrapper;
    }

    /**
     * 导出应用的对话历史为Markdown格式
     *
     * @param appId 应用ID
     * @param loginUser 登录用户
     * @return Markdown格式的对话历史内容
     */
    @Override
    public String exportChatHistoryToMarkdown(Long appId, User loginUser) {
        // 基础参数校验
        ThrowUtils.throwIf(appId == null || appId <= 0, ErrorCode.PARAMS_ERROR, "应用ID不能为空");
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR);

        // 验证应用是否存在
        App app = appService.getById(appId);
        ThrowUtils.throwIf(app == null, ErrorCode.NOT_FOUND_ERROR, "应用不存在");

        // 验证权限：只有应用创建者和管理员可以导出
        boolean isAdmin = UserConstant.ADMIN_ROLE.equals(loginUser.getUserRole());
        boolean isCreator = app.getUserId().equals(loginUser.getId());
        ThrowUtils.throwIf(!isAdmin && !isCreator, ErrorCode.NO_AUTH_ERROR, "无权导出该应用的对话历史");

        // 查询该应用的所有对话历史，按时间正序排列
        QueryWrapper queryWrapper = QueryWrapper.create()
                .eq(ChatHistory::getAppId, appId)
                .orderBy(ChatHistory::getCreateTime, true); // 按创建时间正序排列

        List<ChatHistory> historyList = this.list(queryWrapper);

        // 构建Markdown内容
        StringBuilder markdown = new StringBuilder();

        // 添加标题和基本信息
        markdown.append("# ").append(app.getAppName()).append(" - 对话历史\n\n");
        markdown.append("**应用名称:** ").append(app.getAppName()).append("\n\n");
        markdown.append("**应用初始化提示:** ").append(StrUtil.isNotBlank(app.getInitPrompt()) ? app.getInitPrompt() : "无初始化提示").append("\n\n");
        markdown.append("**导出时间:** ").append(LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).append("\n\n");
        markdown.append("**对话数量:** ").append(historyList.size()).append(" 条\n\n");
        markdown.append("---\n\n");

        // 如果没有对话历史
        if (CollUtil.isEmpty(historyList)) {
            markdown.append("暂无对话记录。\n");
            return markdown.toString();
        }

        // 遍历对话历史，构建Markdown格式的对话内容
        String currentDate = "";
        for (ChatHistory history : historyList) {
            String messageDate = history.getCreateTime().toLocalDate().toString();

            // 如果是新的日期，添加日期分组
            if (!messageDate.equals(currentDate)) {
                currentDate = messageDate;
                markdown.append("## ").append(messageDate).append("\n\n");
            }

            // 根据消息类型添加不同的格式
            String timeStr = history.getCreateTime().format(java.time.format.DateTimeFormatter.ofPattern("HH:mm:ss"));

            if (ChatHistoryMessageTypeEnum.USER.getValue().equals(history.getMessageType())) {
                // 用户消息
                markdown.append("### 👤 用户 (").append(timeStr).append(")\n\n");
                markdown.append(history.getMessage()).append("\n\n");
            } else if (ChatHistoryMessageTypeEnum.AI.getValue().equals(history.getMessageType())) {
                // AI消息
                markdown.append("### 🤖 AI助手 (").append(timeStr).append(")\n\n");
                markdown.append(history.getMessage()).append("\n\n");
            }

            markdown.append("---\n\n");
        }

        return markdown.toString();
    }
}
